/*
 * ESP32-S3 BLE 配网程序
 * 功能：通过蓝牙接收手机端发送的WiFi配置(SSID/密码)，返回设备连接状态
 * 协议规范参考：蓝牙4.2 GATT协议，JSON数据交互格式
 */

// 引入蓝牙库及JSON解析库（需安装 ArduinoJson）
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <ArduinoJson.h>
//#include <esp_bt.h>  // 添加蓝牙头文件

// 定义BLE服务与特征值UUID（需与手机端一致）
#define SERVICE_UUID "91a9c0a0-1b3d-11ee-be56-0242ac120002"       // 主服务标识
#define CHARACTERISTIC_RX "91a9c0a1-1b3d-11ee-be56-0242ac120002"  // 接收配置特征值
#define CHARACTERISTIC_TX "91a9c0a2-1b3d-11ee-be56-0242ac120002"  // 发送状态特征值

// 全局变量声明
BLECharacteristic *pTxCharacteristic;  // 用于发送状态的特征值对象指针
bool deviceConnected = false;          // 蓝牙连接状态标志位
String deviceMac;                      // 存储设备MAC地址
int status = 0;                        // 状态码（0:连接中,1:失败,2:成功）
int code = 0;

// 获取设备蓝牙MAC地址并格式化为字符串 ----去除，需先完成蓝牙的启动才可调用当前函数
String getMacAddress() {
  String macAddress = BLEDevice::getAddress().toString().c_str();
  //macAddress.replace(":", "");     // 去除冒号
  return macAddress;  // 取后字符位数
}
/* BLE服务器回调类
 * 处理连接/断开事件
 */
class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer *pServer) {
    deviceConnected = true;              // 更新连接状态
    Serial.println("Device Connected");  // 串口输出连接提示
  }

  void onDisconnect(BLEServer *pServer) {
    deviceConnected = false;
    pServer->startAdvertising();  // 断开后重新开始广播
    Serial.println("Device Disconnected");
  }
};

/* 数据接收回调类
 * 处理手机端写入的WiFi配置数据
 */
class RxCallbacks : public BLECharacteristicCallbacks {
private:
  String buffer;                     // 数据缓冲区
  unsigned long lastRxTime;          // 最后接收时间戳
  const uint32_t RX_TIMEOUT = 3000;  // 超时时间(ms)
  int connectionStatus = 2;          // 0:连接中 1:失败 2:成功
  int status = 0;                    // 验证码存储
public:
  RxCallbacks()
    : lastRxTime(0) {}

  void onWrite(BLECharacteristic *pChar) {
    // 获取新数据片段并追加到缓冲区
    String fragment = pChar->getValue().c_str();
    buffer += fragment;
    lastRxTime = millis();

    // 调试输出：显示当前接收进度
    Serial.printf("Received %d bytes, buffer size: %d\n",
                  fragment.length(), buffer.length());

    // 检测结束符（假设数据以换行符结束）
    int endIndex = buffer.indexOf('\n');
    if (endIndex != -1) {
      // 提取完整数据（不含结束符）
      String completeData = buffer.substring(0, endIndex);

      // 处理完整数据
      processData(completeData);

      // 保留未处理数据（如果有多个数据包粘包）
      buffer = buffer.substring(endIndex + 1);
    }

    // 缓冲区溢出保护（最大允许4KB）
    if (buffer.length() > 4096) {
      Serial.println("Buffer overflow! Clearing...");
      buffer = "";
    }
  }

  // 超时检测函数（需在loop()中定期调用）
  void checkTimeout() {
    if (buffer.length() > 0 && (millis() - lastRxTime) > RX_TIMEOUT) {
      Serial.println("Timeout, clear buffer");
      buffer = "";
    }
  }

  // 数据处理示例
  void processData(String &data) {
    Serial.print("完整数据: ");
    Serial.println(data);
    DynamicJsonDocument doc(256);
    deserializeJson(doc, data);  // 反序列化JSON字符串
    // DeserializationError error = deserializeJson(doc, rxValue);
    // if (error) { // 新增：错误处理
    //   Serial.print("JSON解析失败: ");
    //   Serial.println(error.c_str());
    //   return;
    // }

    // 提取配置参数
    String ssid = doc["deviceConfig"]["ssid"].as<String>();
    String password = doc["deviceConfig"]["password"].as<String>();
    String userid = doc["deviceConfig"]["userid"].as<String>();
    Serial.println(ssid);      //串口打印解析的JSON
    Serial.println(password);  //串口打印解析的JSON
    Serial.println(userid);    //串口打印解析的JSON

    // 构建JSON数据结构（优化内存管理）
    DynamicJsonDocument doc_tr(128);
    JsonObject devicestatus = doc_tr.createNestedObject("devicestatus");

    devicestatus["Device-Id"] = deviceMac;    // 使用正确MAC地址
    devicestatus["status"] = String(status);  // 状态码转字符串
    devicestatus["code"] = String(code);      // 数字类型直接存储

    // 序列化JSON
    String output;
    serializeJson(doc_tr, output);

    Serial.print("发送状态：");
    Serial.println(output);

    pTxCharacteristic->setValue(output.c_str());
    pTxCharacteristic->notify();
  }
};

// 全局实例化


/* 初始化函数
 * 硬件与协议栈初始化
 */
void setup() {
  Serial.begin(115200);  // 初始化串口（调试输出）

  String deviceName = "Lumina_988669";  // 取M名称
  // deviceName.replace(":", "");        // 去除冒号（符合蓝牙名称规范）
  // 初始化BLE设备
  BLEDevice::init(deviceName.c_str());  // 设置可发现的设备名称
  // BLEDevice::setMTU(256);//如果MTU设置过早（如init前）会导致崩溃，过晚（如广播后）可能无法生效 ---无效
  // Serial.println(BLEDevice::getMTU());
  BLEServer *pServer = BLEDevice::createServer();  // 创建GATT服务器
  pServer->setCallbacks(new MyServerCallbacks());  // 绑定连接事件回调

  // 创建主服务
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // 配置RX特征值（接收配置）
  BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_RX,
    BLECharacteristic::PROPERTY_WRITE  // 手机端可写入
  );
  pRxCharacteristic->setCallbacks(new RxCallbacks());  // 绑定数据接收回调

  // 配置TX特征值（发送状态）
  pTxCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_TX,
    BLECharacteristic::PROPERTY_READ |    // 手机端可读取
      BLECharacteristic::PROPERTY_NOTIFY  // 启用通知功能
  );

  // 启动BLE服务
  pService->start();

  // 配置广播参数（优化连接速度与功耗）
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);  // 广播中包含服务UUID
  pAdvertising->setScanResponse(true);         // 启用扫描响应
  pAdvertising->setMinInterval(0x20);          // 最小广播间隔32 * 0.625ms=20ms
  pAdvertising->setMaxInterval(0x40);          // 最大间隔64 * 0.625ms=40ms
  BLEDevice::startAdvertising();               // 开始广播
  deviceMac = getMacAddress();
  if (code == 0) {  // 生成新验证码规则：仅在初始状态生成
    code = random(100000, 999999);
  }
  Serial.println("蓝牙BLE开始调试输出");  // 调试输出
}

/* 主循环
 * 监控连接状态（可扩展WiFi连接逻辑）
 */
void loop() {
  if (deviceConnected) {
    // 示例：可在此添加WiFi连接状态检测
    // 例如：检查WiFi连接成功后更新statusCode=2
    delay(1000);  // 防止频繁轮询
  }
}